package anatex.kea.genex.genitor;

import java.util.ArrayList;

public class Crossover {
	
	protected Double mutationRate;
	protected Double averageFitness;
	
	public Crossover() {
		averageFitness = 0.0;
		mutationRate = 0.2;
	}
	
	public void setAverageFitness(Double avgFit) {
		averageFitness = avgFit;
	}
	
	//TODO Finish implementation of mutation operation
	public void mutate(String[] parents, String child) {
		//calculate the hamming distance against each parent
		int distance;
		Boolean mustMutate = false;
		
		for (String parent : parents) {
			distance = 0;
			for (int i = 0; i < parent.length(); i ++) {
				if (parent.charAt(i) != child.charAt(i)) {
					distance ++;
				}
			}
			
			if (distance / parent.length() < mutationRate) {
				mustMutate = true;
				
				break;
			}
		}
		
		if (! mustMutate) {
			return;
		}
		
		//obviously will mutate
//		System.out.println("Will mutate");
		int l = child.length();
		char[] chars = new char[l]; 
		child.getChars(0, l, chars, 0);
		
		for (int i = 0; i < l; i ++) {
			if (Math.random() < mutationRate) {
				chars[i] = '1' == chars[i] ? '0' : '1';
				
//				System.out.println("\tmutation @ " + i);
			}
		}
		
		child = new String(chars);
	}
	
	public String crossover(String p1, String p2) {
		String child = "";
		
		ArrayList<Integer> crossoverPoints = new ArrayList<Integer>();
		
		for (int i = 0; i < p1.length(); i ++) {
			if (p1.charAt(i) != p2.charAt(i)) {
				crossoverPoints.add(i + 1);
			}
		}
		
		if (crossoverPoints.size() == 1 && (1 == crossoverPoints.get(0) || p1.length() == crossoverPoints.get(0))) {
			if (1 == (int)(Math.floor(Math.random() * 2))) {
				child = p2;
			} else {
				child = p1;
			}
		} else {
			int crossoverPoint = crossoverPoints.get((int)(Math.ceil(Math.random() * crossoverPoints.size())) - 1);
			
			child = p1.substring(0, crossoverPoint) + p2.substring(crossoverPoint);
			
//			System.out.println("Parent is long " + p1.length() + " while child is " + child.length());
//			
//			System.out.println("A new child is born " + child);
		}
		
		return child;
	}
	
}
